package com.peas.platform.module.icims.base.approve.api;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.peas.platform.common.core.configuration.RequestContextUtil;
import com.peas.platform.common.core.dto.ResponseDto;
import com.peas.platform.common.core.enums.BaseEnum;
import com.peas.platform.common.core.exception.BaseException;
import com.peas.platform.framework.mybatisplus.annotation.ConditionOperator;
import com.peas.platform.module.icims.base.approve.api.req.SaveApproveVo;
import com.peas.platform.module.icims.base.approve.api.req.SendApproveVo;
import com.peas.platform.module.icims.base.approve.api.resp.ApproveOrderOperResp;
import com.peas.platform.module.icims.base.approve.dto.*;
import com.peas.platform.module.icims.base.approve.enums.*;
import com.peas.platform.module.icims.base.approve.service.*;
import com.peas.platform.module.icims.base.auth.dto.OrganizationDto;
import com.peas.platform.module.icims.base.auth.dto.RoleDto;
import com.peas.platform.module.icims.base.auth.dto.UserDto;
import com.peas.platform.module.icims.base.auth.service.OrganizationService;
import com.peas.platform.module.icims.base.auth.service.RoleService;
import com.peas.platform.module.icims.base.auth.service.UserService;
import com.peas.platform.module.icims.base.dict.dto.DictValueDto;
import com.peas.platform.module.icims.base.dict.service.DictValueService;
import com.peas.platform.module.icims.base.sys.enums.CommonYesNo;
import com.peas.platform.module.icims.base.sys.enums.Module;
import com.peas.platform.module.icims.base.sys.service.AttachmentService;
import com.peas.platform.module.icims.expenditure.expenses.enums.ExpenditureReimbursementFeetype;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Api(tags = "自定义接口-审批流")
@RestController
@RequestMapping("/api/v1/customApprove")
@Slf4j
public class CustomApproveController {

    @Resource
    private ApproveService approveService;
    @Resource
    private ApproveOrderService approveOrderService;
    @Resource
    private ApproveOrderTobeService approveOrderTobeService;
    @Resource
    private DictValueService dictValueService;
    @Resource
    private ApproveOrderNodeService approveOrderNodeService;
    @Resource
    private ApproveOrderOperService approveOrderOperService;
    @Resource
    private UserService userService;
    @Resource
    private OrganizationService organizationService;
    @Resource
    private RoleService roleService;
    @Resource
    private AttachmentService attachmentService;

    private static JSONObject buildObject(BaseEnum baseEnum) {
        JSONObject o = new JSONObject();
        o.set("key", baseEnum.getKey());
        o.set("value", baseEnum.getValue());
        return o;
    }

    @ApiOperation(value = "查询审批配置")
    @GetMapping("/approveConfig")
    public ResponseDto<List<JSONObject>> approveConfig() {
        List<Module> sub1 = Arrays.asList(Module.values());
        List<JSONObject> subList1 = sub1.stream().map(CustomApproveController::buildObject).collect(Collectors.toList());
        subList1.forEach(module -> {
            List<ApproveBusiness> sub2 = Arrays.stream(ApproveBusiness.values()).filter(ab -> ab.getModule().getKey().equals(module.getStr("key"))).collect(Collectors.toList());
            List<JSONObject> subList2 = sub2.stream().map(CustomApproveController::buildObject).collect(Collectors.toList());
            subList2.forEach(approveBusiness -> {
                List<ApproveBusinessField> sub3 = Arrays.stream(ApproveBusinessField.values()).filter(ab -> ab.getApproveBusiness().getKey().equals(approveBusiness.getStr("key"))).collect(Collectors.toList());
                List<JSONObject> subList3 = sub3.stream().map(CustomApproveController::buildObject).collect(Collectors.toList());
                subList3.forEach(o -> {
                    ConditionOperator valueType = null;
                    List<JSONObject> subList4 = new ArrayList<>();
                    ApproveBusinessField abf = BaseEnum.key2Enum(ApproveBusinessField.class, o.getStr("key"));
                    switch (abf) {
                        // 经费类型
                        case expenditureKpi001:
                        case expenditureQuota001:
                        case expenditureAdjustment001:
                        case expenditureApplication001:
                        case expenditureReimbursement001:
                        case expenditureReimbursementOther001:
                            List<DictValueDto> list1 = dictValueService.listByField("dictType", "ExpenditureKpiFundType");
                            subList4 = list1.stream().map(dict -> {
                                JSONObject json = new JSONObject();
                                json.set("key", dict.getDictKey());
                                json.set("value", dict.getDictValue());
                                return json;
                            }).collect(Collectors.toList());
                            valueType = ConditionOperator.IN;
                            break;
                        // 财政项目分类
                        case expenditureKpi002:
                        case expenditureQuota002:
                        case expenditureAdjustment002:
                        case expenditureApplication002:
                        case expenditureReimbursement002:
                        case expenditureReimbursementOther002:
                            List<DictValueDto> list2 = dictValueService.listByField("dictType", "ExpenditureFiscal");
                            subList4 = list2.stream().map(dict -> {
                                JSONObject json = new JSONObject();
                                json.set("key", dict.getDictKey());
                                json.set("value", dict.getDictValue());
                                return json;
                            }).collect(Collectors.toList());
                            valueType = ConditionOperator.IN;
                            break;
                        // 金额限制
                        case expenditureKpi003:
                        case expenditureQuota003:
                        case expenditureAdjustment003:
                        case expenditureApplication003:
                        case expenditureReimbursement003:
                        case expenditureReimbursementOther003:
                            valueType = ConditionOperator.BETWEEN;
                            break;
                        // 费用类型
                        case expenditureReimbursement004:
                            List<ExpenditureReimbursementFeetype> list4 = Arrays.asList(ExpenditureReimbursementFeetype.values());
                            subList4 = list4.stream().map(e -> {
                                JSONObject json = new JSONObject();
                                json.set("key", e.getKey());
                                json.set("value", e.getValue());
                                return json;
                            }).collect(Collectors.toList());
                            valueType = ConditionOperator.IN;
                            break;
                    }
                    o.set("valueType", valueType);
                    o.set("children", subList4);
                });
                approveBusiness.set("children", subList3);
            });
            module.set("children", subList2);
        });
        return ResponseDto.getSuccessResponseDto(subList1);
    }

    @ApiOperation(value = "查询匹配的审批模版")
    @GetMapping("/queryApproveByBusiness")
    public ResponseDto<List<ApproveDto>> queryApproveByBusiness(String business, Long businessId) {
        ApproveBusiness ab = BaseEnum.key2Enum(ApproveBusiness.class, business);
        Assert.notNull(ab, "业务类型为空或取值不正确");
        List<ApproveDto> list = approveService.queryApproveByBusiness(ab, businessId);
        return ResponseDto.getSuccessResponseDto(list);
    }

    @ApiOperation(value = "保存审批模版")
    @PostMapping("/saveApprove")
    public ResponseDto<Boolean> saveApprove(@RequestBody @Valid SaveApproveVo vo) {
        log.info("vo:" + vo);
        ApproveType approveType = BaseEnum.key2Enum(ApproveType.class, vo.getApproveType());
        switch (approveType) {
            case global:
                vo.setModule("-1");
                vo.setBusiness("-1");
                break;
            case module:
                vo.setBusiness("-1");
                break;
            case business:
            case conditional:
                break;
        }
        approveService.saveApprove(vo);
        return ResponseDto.getSuccessResponseDto(true);
    }

    @ApiOperation(value = "执行审批")
    @PostMapping("/sendApprove")
    public ResponseDto<Boolean> sendApprove(@RequestBody @Valid SendApproveVo vo) {
        approveOrderService.approve(vo.getApproveOrderId(), vo.getApproveResult(), vo.getApproveOpinion());
        return ResponseDto.getSuccessResponseDto(true);
    }

    @ApiOperation(value = "查看待阅")
    @PostMapping(value = "/readApproveTobe/{id}")
    public ResponseDto<Boolean> readApproveTobe(@PathVariable(value = "id") Long id) {
        ApproveOrderTobeDto dto = approveOrderTobeService.getById(id);
        Assert.notNull(dto, "找不到待阅信息");
        Assert.equals(dto.getReceiveUserId(), Long.valueOf(RequestContextUtil.getCurrentUserId(true)), "该待阅数据错误");
        if (StrUtil.equals(ApproveOrderTobeType.todo.getKey(), dto.getApproveOrderTobeType())) {
            return ResponseDto.getSuccessResponseDto(true);
        }
        if (dto.getReadTime() == null)
            dto.setReadTime(DateTime.now());
        dto.setState(ApproveOrderTobeState.done.getKey());
        approveOrderTobeService.updateById(dto);
        return ResponseDto.getSuccessResponseDto(true);
    }

    @ApiOperation(value = "查询审批记录")
    @GetMapping(value = "/queryApproveOrderOper")
    public ResponseDto<List<ApproveOrderOperResp>> queryApproveOrderOper(@RequestParam(value = "businessType", required = false) String businessType, @RequestParam(value = "businessId", required = false) Long businessId) {
        Assert.notBlank(businessType, "业务类型不能为空");
        Assert.notNull(businessId, "业务单ID不能为空");
        ApproveOrderDto c = new ApproveOrderDto();
        c.setBusinessType(businessType);
        c.setBusinessId(businessId);
        ApproveOrderDto aod = approveOrderService.getOne(c, false);
        if (aod == null) {
            return ResponseDto.getSuccessResponseDto(Collections.emptyList());
        }
        List<ApproveOrderOperResp> r = new ArrayList<>();
        AtomicInteger idx = new AtomicInteger(1);
        ApproveOrderNodeDto c1 = new ApproveOrderNodeDto();
        c1.setApproveOrderId(aod.getId());
        List<ApproveOrderNodeDto> list1 = approveOrderNodeService.list(c1);
        if (CollUtil.isNotEmpty(list1)) {
            List<ApproveOrderOperResp> r1 = list1.stream().map(dto -> {
                ApproveOrderOperResp o = new ApproveOrderOperResp();
                o.setId(dto.getId());
                o.setIndex(idx.getAndIncrement());
                o.setApproveOrderId(aod.getId());
                o.setApproveOrderOperType(ApproveOrderOperType.approve.getKey());
                o.setApproveResult(null);
                o.setApproveOpinion(null);
                o.setBusinessType(businessType);
                o.setBusinessId(businessId);
                o.setColor("");
                ApproveNodeType approveNodeType = BaseEnum.key2Enum(ApproveNodeType.class, dto.getApproveNodeType());
                o.setApproveNodeType(dto.getApproveNodeType());
                switch (approveNodeType) {
                    case org: {
                        Assert.notBlank(dto.getApproveNodeOrgId(), "审批节点组织架构为空");
                        o.setCurrentApproveIds(dto.getApproveNodeOrgId());
                        List<Long> orgIds = StrUtil.split(dto.getApproveNodeOrgId(), ",").stream().map(Long::valueOf).collect(Collectors.toList());
                        List<OrganizationDto> orgs = organizationService.listByIds(orgIds);
                        String names = CollUtil.join(orgs.stream().map(OrganizationDto::getOrganizationName).collect(Collectors.toList()), ",");
                        o.setCurrentApproveNames(names);
                        break;
                    }
                    case user: {
                        Assert.notBlank(dto.getApproveNodeUserId(), "审批节点用户为空");
                        o.setCurrentApproveIds(dto.getApproveNodeUserId());
                        List<Long> userIds = StrUtil.split(dto.getApproveNodeUserId(), ",").stream().map(Long::valueOf).collect(Collectors.toList());
                        List<UserDto> users = userService.listByIds(userIds);
                        String names = CollUtil.join(users.stream().map(UserDto::getName).collect(Collectors.toList()), ",");
                        o.setCurrentApproveNames(names);
                        o.setCurrentApproveUserId(dto.getApproveNodeUserId());
                        o.setCurrentApproveUserName(names);
                        break;
                    }
                    case role: {
                        Assert.notBlank(dto.getApproveNodeRoleId(), "审批节点角色为空");
                        o.setCurrentApproveIds(dto.getApproveNodeRoleId());
                        List<Long> roleIds = StrUtil.split(dto.getApproveNodeRoleId(), ",").stream().map(Long::valueOf).collect(Collectors.toList());
                        List<RoleDto> roles = roleService.listByIds(roleIds);
                        String names = CollUtil.join(roles.stream().map(RoleDto::getRoleName).collect(Collectors.toList()), ",");
                        o.setCurrentApproveNames(names);
                        break;
                    }
                }
                o.setCurrentName(dto.getApproveNodeName());
                o.setCurrentNo(dto.getApproveNodeNo());
                o.setSignImg(null);
                o.setHollow(true);
                o.setIsCountersign(dto.getIsCountersign());
                if (StrUtil.isNotBlank(o.getCurrentName())) {
                    o.setTitle("第" + o.getCurrentNo() + "节点：" + o.getCurrentName());
                }
                o.setTimestamp(null);
                return o;
            }).collect(Collectors.toList());
            log.warn("r1:" + r1);
            r.addAll(r1);
        }
        ApproveOrderOperDto c2 = new ApproveOrderOperDto();
        c2.setBusinessType(businessType);
        c2.setBusinessId(businessId);
        List<ApproveOrderOperDto> list2 = approveOrderOperService.list(c2);
        if (CollUtil.isNotEmpty(list2)) {
            List<Long> userIds = CollUtil.distinct(list2.stream().map(ApproveOrderOperDto::getCurrentApproveUserId).collect(Collectors.toList()));
            List<UserDto> users = userService.listByIds(userIds);
            List<ApproveOrderOperResp> r2 = list2.stream().map(dto -> {
                ApproveOrderOperResp o = new ApproveOrderOperResp();
                o.setId(dto.getId());
                o.setIndex(idx.getAndIncrement());
                o.setApproveOrderId(aod.getId());
                o.setApproveOrderOperType(dto.getApproveOrderOperType());
                o.setApproveResult(dto.getApproveResult());
                o.setApproveOpinion(dto.getApproveOpinion());
                o.setBusinessType(businessType);
                o.setBusinessId(businessId);
                ApproveOrderOperType approveOrderOperType = BaseEnum.key2Enum(ApproveOrderOperType.class, o.getApproveOrderOperType());
                ApproveResult approveResult = BaseEnum.key2Enum(ApproveResult.class, o.getApproveResult());
                UserDto user = users.stream().filter(userDto -> dto.getCurrentApproveUserId().equals(userDto.getId())).findFirst().orElse(null);
                switch (approveOrderOperType) {
                    case submit:
                        o.setTitle(ApproveOrderOperType.submit.getValue());
                        o.setColor("#888888");
                        break;
                    case revocation:
                        o.setTitle(ApproveOrderOperType.revocation.getValue());
                        o.setColor("#888888");
                        break;
                    case approve:
                        switch (approveResult) {
                            case pass:
                                o.setColor("#1ab394");
                                break;
                            case reject:
                                o.setColor("#e65d6e");
                                break;
                            default:
                                throw new BaseException("数据错误");
                        }
                        if (user != null && user.getSign() != null) {
                            InputStream is = attachmentService.getObject(user.getSign());
                            String img = "data:image/gif;base64," + Base64.encode(is);
                            o.setSignImg(img);
                        }
                        break;
                }
                o.setApproveNodeType(ApproveNodeType.user.getKey());
                o.setCurrentApproveIds(String.valueOf(dto.getCurrentApproveUserId()));
                o.setCurrentApproveUserId(String.valueOf(dto.getCurrentApproveUserId()));
                if (user != null) {
                    o.setCurrentApproveNames(user.getName());
                    o.setCurrentApproveUserName(user.getName());
                }
                o.setCurrentName(dto.getCurrentName());
                o.setCurrentNo(dto.getCurrentNo());
                o.setHollow(false);
                o.setIsCountersign(CommonYesNo.no.getKey());
                if (StrUtil.isNotBlank(o.getCurrentName()))
                    o.setTitle("第" + o.getCurrentNo() + "节点：" + o.getCurrentName());
                o.setTimestamp(dto.getCreateTime());
                return o;
            }).collect(Collectors.toList());
            log.warn("r2:" + r2);
            r.addAll(r2);
        }
        return ResponseDto.getSuccessResponseDto(r);
    }

}
